package com.yichi.service;

import android.util.Log;

import com.jeremyliao.liveeventbus.LiveEventBus;
import com.licheedev.modbus4android.ModbusCallback;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse;
import com.yichi.device_bean.PlcInfo;
import com.yichi.global.AppConfig;
import com.yichi.global.EventDef;
import com.yichi.manager.ModbusRtuManager;
import com.yichi.manager.ModbusTcpManager;
import com.yichi.util.ByteUtil;
import com.yichi.util.JsonUtil;
import com.yichi.util.Utils;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * PLC（tcp）通讯服务
 */
public class PlcService {

    private static final String TAG = "PlcService";

    private ModbusTcpManager modbusTcpManager;
    private ModbusRtuManager modbusRtuManager;
    private short heartbeatVal = 0;//心跳值交替写入

    /**
     * 单例模式
     */
    public static PlcService inst = new PlcService();

    private PlcService() {
    }

    public void init() {
//        modbusTcpManager = new ModbusTcpManager();
//        modbusTcpManager.initTcp();

        modbusRtuManager = new ModbusRtuManager();
        modbusRtuManager.initPlcTCP();

        //启动心跳
//        ExecutorService executorService1 = Executors.newFixedThreadPool(1);
//        executorService1.execute(new HeartbeatTask());
        //启动查询
//        ExecutorService executorService2 = Executors.newFixedThreadPool(1);
//        executorService2.execute(new QueryDeviceInfoTask());
    }

    //启动查询
    public void startQueryDeviceInfoTask() {
        ExecutorService executorService2 = Executors.newFixedThreadPool(1);
        executorService2.execute(new QueryDeviceInfoTask());
    }

    /**
     * 心跳
     */
    public void writeHeartbeat() {
        int slaveId = AppConfig.PLC_MODBUS_SLAVE_ID;
        int offset = 2000;
        boolean b = modbusTcpManager.writeRegister(slaveId, offset, heartbeatVal);
        if (b) {
            heartbeatVal = (heartbeatVal == 0) ? (short) 1 : (short) 0;
        }
    }

    /**
     * 批量查询PLC的设备信息
     */
    public PlcInfo queryDeviceInfo() {
        try {
            int slaveId = AppConfig.PLC_MODBUS_SLAVE_ID;
            int offset = 1000;
            int count = 11;
//        ArrayList<Short> shorts = modbusTcpManager.readMultipleRegisters(slaveId, offset, count);
//        byte[] bytes = Utils.shortList2ByteArray(shorts);

            byte[] bytes = modbusRtuManager.readMultipleRegistersBytesSync(slaveId, offset, count);
            if (bytes == null || bytes.length <= 0) {
                return null;
            }

            PlcInfo plcInfo = new PlcInfo();
            byte[] tmpByte1 = {bytes[0], bytes[1]};
            int tmpInt1 = Utils.twoBytesToInt(tmpByte1);
            plcInfo.setHeartbeat(tmpInt1);
            byte[] tmpByte2 = {bytes[2], bytes[3]};
            int tmpInt2 = Utils.twoBytesToInt(tmpByte2);
            plcInfo.setOutputDoorStatus1(tmpInt2);
            byte[] tmpByte3 = {bytes[4], bytes[5]};
            int tmpInt3 = Utils.twoBytesToInt(tmpByte3);
            plcInfo.setOutputDoorStatus2(tmpInt3);
            byte[] tmpByte4 = {bytes[6], bytes[7]};
            int tmpInt4 = Utils.twoBytesToInt(tmpByte4);
            plcInfo.setOutputDoorStatus3(tmpInt4);
            byte[] tmpByte5 = {bytes[8], bytes[9]};
            int tmpInt5 = Utils.twoBytesToInt(tmpByte5);
            plcInfo.setOutputBatteryStatus1(tmpInt5);
            byte[] tmpByte6 = {bytes[10], bytes[11]};
            int tmpInt6 = Utils.twoBytesToInt(tmpByte6);
            plcInfo.setOutputBatteryStatus2(tmpInt6);
            byte[] tmpByte7 = {bytes[12], bytes[13]};
            int tmpInt7 = Utils.twoBytesToInt(tmpByte7);
            plcInfo.setOutputBatteryStatus3(tmpInt7);
            byte[] tmpByte8 = {bytes[14], bytes[15]};
            int tmpInt8 = Utils.twoBytesToInt(tmpByte8);
            plcInfo.setInputDoorStatus1(tmpInt8);
            byte[] tmpByte9 = {bytes[16], bytes[17]};
            int tmpInt9 = Utils.twoBytesToInt(tmpByte9);
            plcInfo.setInputDoorStatus2(tmpInt9);
            byte[] tmpByte10 = {bytes[18], bytes[19]};
            int tmpInt10 = Utils.twoBytesToInt(tmpByte10);
            plcInfo.setInputDoorStatus3(tmpInt10);
            byte[] tmpByte11 = {bytes[20], bytes[21]};
            int tmpInt11 = Utils.twoBytesToInt(tmpByte11);
            plcInfo.setBatteryMoveStatus(tmpInt11);

            return plcInfo;
        } catch (Exception e) {
            Log.e(TAG, e.getMessage(), e);
            return null;
        }
    }

    /**
     * 批量查询PLC的设备信息
     */
    public String queryDeviceInfoStr() throws Exception {
        int slaveId = AppConfig.PLC_MODBUS_SLAVE_ID;
        int offset = 1000;
        int count = 11;
        byte[] bytes = modbusRtuManager.readMultipleRegistersBytesSync(slaveId, offset, count);
        return ByteUtil.bytes2HexStr(bytes);
    }

    /**
     * 批量查询PLC的设备信息
     */
    public void queryDeviceInfoCallback(ModbusCallback<ReadHoldingRegistersResponse> callback) {
        int slaveId = AppConfig.PLC_MODBUS_SLAVE_ID;
        int offset = 1000;
        int count = 11;
        modbusRtuManager.readMultipleRegistersCallback(slaveId, offset, count, callback);
    }

    public PlcInfo parsePlcInfo(byte[] bytes) {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }

        PlcInfo plcInfo = new PlcInfo();
        byte[] tmpByte1 = {bytes[0 + 9], bytes[1 + 9]};
        int tmpInt1 = Utils.twoBytesToInt(tmpByte1);
        plcInfo.setHeartbeat(tmpInt1);
        byte[] tmpByte2 = {bytes[2 + 9], bytes[3 + 9]};
        int tmpInt2 = Utils.twoBytesToInt(tmpByte2);
        plcInfo.setOutputDoorStatus1(tmpInt2);
        byte[] tmpByte3 = {bytes[4 + 9], bytes[5 + 9]};
        int tmpInt3 = Utils.twoBytesToInt(tmpByte3);
        plcInfo.setOutputDoorStatus2(tmpInt3);
        byte[] tmpByte4 = {bytes[6 + 9], bytes[7 + 9]};
        int tmpInt4 = Utils.twoBytesToInt(tmpByte4);
        plcInfo.setOutputDoorStatus3(tmpInt4);
        byte[] tmpByte5 = {bytes[8 + 9], bytes[9 + 9]};
        int tmpInt5 = Utils.twoBytesToInt(tmpByte5);
        plcInfo.setOutputBatteryStatus1(tmpInt5);
        byte[] tmpByte6 = {bytes[10 + 9], bytes[11 + 9]};
        int tmpInt6 = Utils.twoBytesToInt(tmpByte6);
        plcInfo.setOutputBatteryStatus2(tmpInt6);
        byte[] tmpByte7 = {bytes[12 + 9], bytes[13 + 9]};
        int tmpInt7 = Utils.twoBytesToInt(tmpByte7);
        plcInfo.setOutputBatteryStatus3(tmpInt7);
        byte[] tmpByte8 = {bytes[14 + 9], bytes[15 + 9]};
        int tmpInt8 = Utils.twoBytesToInt(tmpByte8);
        plcInfo.setInputDoorStatus1(tmpInt8);
        byte[] tmpByte9 = {bytes[16 + 9], bytes[17 + 9]};
        int tmpInt9 = Utils.twoBytesToInt(tmpByte9);
        plcInfo.setInputDoorStatus2(tmpInt9);
        byte[] tmpByte10 = {bytes[18 + 9], bytes[19 + 9]};
        int tmpInt10 = Utils.twoBytesToInt(tmpByte10);
        plcInfo.setInputDoorStatus3(tmpInt10);
        byte[] tmpByte11 = {bytes[20 + 9], bytes[21 + 9]};
        int tmpInt11 = Utils.twoBytesToInt(tmpByte11);
        plcInfo.setBatteryMoveStatus(tmpInt11);
        return plcInfo;
    }

    /**
     * 移动电池
     */
    public void handleMoveBattery(int source, int target) {
        int slaveId = AppConfig.PLC_MODBUS_SLAVE_ID;
        int offset = 2001;

        short[] datas = new short[3];
        datas[0] = 1;
        datas[1] = (short) source;
        datas[2] = (short) target;

//        boolean b = modbusTcpManager.writeRegisters(slaveId, offset, datas);
        modbusRtuManager.writeRegistersCmd(slaveId, offset, datas);
    }

    /**
     * 电池是否移动完成
     * @return
     */
    public boolean isBatteryMoveComplete() {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        Future<Boolean> future = executor.submit(() -> {
            while (true) {
                PlcInfo plcInfo = queryDeviceInfo();
                Log.i(TAG, String.format("电池移动状态：%s", plcInfo.getBatteryMoveStatus()));
                if (plcInfo.getBatteryMoveStatus() == 2) {
                    return true;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        boolean result;
        try {
            result = future.get(); // 阻塞等待，直到任务完成
        } catch (InterruptedException | ExecutionException e) {
            Log.e(TAG, e.getMessage(), e);
            Thread.currentThread().interrupt();
            result = false;
        } finally {
            executor.shutdown();
        }
        return result;
    }

    /**
     * 电池是否移动完成
     */
    public boolean isBatteryMoveCompleteEx() {
        // 创建 CountDownLatch，等待线程结束
        CountDownLatch latch = new CountDownLatch(1);
        final boolean[] result = {false};
        final boolean[] stopFlag = {false}; // 停止标志

        // 启动线程
        Thread thread = new Thread(() -> {
            // 无限循环，直到找到
            while (!stopFlag[0]) {
                PlcInfo plcInfo = queryDeviceInfo();
                Log.i(TAG, String.format("电池移动状态：%s", plcInfo.getBatteryMoveStatus()));
                if (plcInfo.getBatteryMoveStatus() == 2) {
                    break;
                }

                try {
                    Thread.sleep(1000); // 休眠一段时间，避免 CPU 过度占用
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            result[0] = true;//保存结果
            latch.countDown(); // 通知主线程完成
        });
        thread.start();

        try {
            // 等待子线程完成，最多等待 5 秒
            boolean completed = latch.await(60, TimeUnit.SECONDS);//预测电池移动完成需要5秒，要调整？
            if (completed) {
                // 子线程在5秒内完成，返回其结果
                return result[0];
            } else {
                // 超时未完成
                System.out.println("Timeout reached.");
                return false;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        } finally {
            stopFlag[0] = true; // 超时后设置停止标志
        }
    }

    /**
     * 打开仓门
     * 编号，1 2 3 4 5 6
     */
    public void handleOpenDoor(int storeNo) {
        int slaveId = AppConfig.PLC_MODBUS_SLAVE_ID;
        int offset = 2004;

        short[] datas = new short[1];
        datas[0] = (short) storeNo;

//        boolean b = modbusTcpManager.writeRegisters(slaveId, offset, datas);
        modbusRtuManager.writeRegistersCmd(slaveId, offset, datas);
    }

    /**
     * 是否打卡仓门
     * 5秒后超时
     *
     * @return
     */
    public boolean isOpenDoor(Integer storeNo) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Boolean> future = executor.submit(() -> {
            long startTime = System.currentTimeMillis();
            while (System.currentTimeMillis() - startTime < 5000) { // 5秒超时
                PlcInfo plcInfo = queryDeviceInfo();
                if (plcInfo != null) {
                    Integer doorStatusByStoreNo = plcInfo.getDoorStatusByStoreNo(storeNo);
                    if (doorStatusByStoreNo == 0) {
                        return true; // 条件达成
                    }
                }
                try {
                    Thread.sleep(1500); // 轮询间隔
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return false; // 如果线程被中断，返回false
                }
            }
            return false; // 超时
        });

        try {
            return future.get(); // 阻塞等待结果
        } catch (InterruptedException | ExecutionException e) {
            Thread.currentThread().interrupt();
            return false;
        } finally {
            executor.shutdown(); // 关闭线程池
        }
    }

    /**
     * 是否关闭仓门
     * 没关门会一直等待
     *
     * @return
     */
    public PlcInfo isCloseDoor(Integer storeNo) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<PlcInfo> future = executor.submit(() -> {
            while (true) { // 一直等到关门
                PlcInfo plcInfo = queryDeviceInfo();
                if (plcInfo != null) {
                    Integer doorStatusByStoreNo = plcInfo.getDoorStatusByStoreNo(storeNo);
                    if (doorStatusByStoreNo == 1) {
                        return plcInfo; // 条件达成
                    }
                }
                try {
                    Thread.sleep(1000); // 轮询间隔
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return null; // 如果线程被中断，返回false
                }
            }
        });

        try {
            return future.get(); // 阻塞等待结果
        } catch (InterruptedException | ExecutionException e) {
            Thread.currentThread().interrupt();
            return null;
        } finally {
            executor.shutdown(); // 关闭线程池
        }
    }

    /**
     * 移动电机
     * 0停止 1上 2下 3左 4右 5前 6后
     *
     * @param val
     * @return
     */
    public void handleMotor(int val) {
        int slaveId = AppConfig.PLC_MODBUS_SLAVE_ID;
        int offset = 2005;

        short[] datas = new short[1];
        datas[0] = (short) val;

//        boolean b = modbusTcpManager.writeRegisters(slaveId, offset, datas);
        modbusRtuManager.writeRegistersCmd(slaveId, offset, datas);
    }

    /**
     * 重置电池移动状态
     */
    public void resetMoveStatus() {
        int slaveId = AppConfig.PCB_MODBUS_SLAVE_ID;
        int offset = 1010;

        short[] shortArray = new short[1];
        shortArray[0] = 0;

        modbusRtuManager.writeRegistersCmd(slaveId, offset, shortArray);
    }

    /**
     * 设置X轴速度
     * @param v 0-100
     */
    public void setSpeedX(Integer v) {
        int slaveId = AppConfig.PCB_MODBUS_SLAVE_ID;
        int offset = 2006;

        byte[] bytes = new byte[2];
        bytes[0] = 0x00;
        bytes[1] = Utils.intToOneByte(v);

        short[] shorts = Utils.byteArray2ShortArray(bytes);
        modbusRtuManager.writeRegistersCmd(slaveId, offset, shorts);
    }

    /**
     * 设置Y轴速度
     * @param v 0-100
     */
    public void setSpeedY(Integer v) {
        int slaveId = AppConfig.PCB_MODBUS_SLAVE_ID;
        int offset = 2007;

        byte[] bytes = new byte[2];
        bytes[0] = 0x00;
        bytes[1] = Utils.intToOneByte(v);

        short[] shorts = Utils.byteArray2ShortArray(bytes);
        modbusRtuManager.writeRegistersCmd(slaveId, offset, shorts);
    }

    /**
     * 设置Z轴速度
     * @param v 0-100
     */
    public void setSpeedZ(Integer v) {
        int slaveId = AppConfig.PCB_MODBUS_SLAVE_ID;
        int offset = 2008;

        byte[] bytes = new byte[2];
        bytes[0] = 0x00;
        bytes[1] = Utils.intToOneByte(v);

        short[] shorts = Utils.byteArray2ShortArray(bytes);
        modbusRtuManager.writeRegistersCmd(slaveId, offset, shorts);
    }

    /**
     * 心跳任务
     */
    public class HeartbeatTask implements Runnable {

        @Override
        public void run() {
            while (true) {
                writeHeartbeat();
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    Log.e(TAG, e.getMessage(), e);
                }
            }
        }

    }

    /**
     * 查询任务
     */
    public class QueryDeviceInfoTask implements Runnable {

        @Override
        public void run() {
            while (true) {
                PlcInfo plcInfo = queryDeviceInfo();
                LiveEventBus.get(EventDef.EVENT_PLC_INFO_QUERY_TASK, PlcInfo.class).post(plcInfo);
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    Log.e(TAG, e.getMessage(), e);
                }
            }
        }

    }

    public void testCmd() {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    PlcInfo plcInfo = queryDeviceInfo();
                    Log.i(TAG, "pcb测试结果:" + JsonUtil.toJSONString(plcInfo));
                } catch (Exception e) {
                    Log.e(TAG, "IC Card query failed", e);
                }

                try {
                    Thread.sleep(3000); // Sleep for 100ms (adjust as needed)
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start(); // Start the background thread
    }

}
